#! /usr/bin/env python
# -*- coding: utf-8 -*-

import gtk
import gobject
from gtk import gdk
import pygtk
from math import pi, atan2, sin, cos, radians

from plane import Plane

class OrthoGTK(gtk.DrawingArea):
    def __init__(self, pixbuf):
        self.colors = [[1,0,0], [0,0,1], [0,1,0], [1,1,0], [1,0,1], [0,1,1]]
        gtk.DrawingArea.__init__(self)
        self.pixbuf = pixbuf
        self.width, self.height = pixbuf.get_width(), pixbuf.get_height()
        self.set_size_request (self.width, self.height)
        self.cx, self.cy = self.width/2, self.height/2
        self.connect("expose_event", self.expose)

        self.pairs = [] # list of pairs of conj
        self.cur_pair = [] # curently selected pair
        self.cur_max = [] # currently selected max
        self.cur_belt = None
        self.scats = None # scats directions ans their length to plot
        self.belts = []
        self.cur_belt = None
    
    def expose(self, widget, event):        
        context = widget.window.cairo_create()
        # set a clip region for the expose event
        context.rectangle(event.area.x, event.area.y,
                               event.area.width, event.area.height)
        context.clip()
        context.set_source_pixbuf(self.pixbuf,0,0)
        context.paint()
        context.stroke()   

        self.Draw(context)
    
    def Draw(self,context):
        # draw belts
        for b in self.belts:
            self.draw_Belt(context, b)

        # draw curent belt:
        if self.cur_belt:
            self.draw_Belt(context, self.cur_belt, col=[1,0,0])

        # draw scats:
        if self.scats:
            self.draw_Scats(context, self.scats)
        # draw pairs
        for i, pair in enumerate(self.pairs):
            color = self.colors[i% len(self.colors)]
            self.draw_Arrow(context, pair[0], pair[1], color)
            self.draw_Point(context, pair[0], color)
            self.draw_Arrow(context, pair[2], pair[3], color)
            self.draw_Point(context, pair[2], color)
        # draw cur_pair
        if self.cur_pair:
            self.draw_GreatCircle(context, self.cur_pair[0], self.cur_pair[2])
            self.draw_Arrow(context, self.cur_pair[0], self.cur_pair[1],[0,0,0])
            self.draw_Point(context, self.cur_pair[0], [0,0,0])
            self.draw_Arrow(context, self.cur_pair[2], self.cur_pair[3],[0,0,0])
            self.draw_Point(context, self.cur_pair[2], [0,0,0])
            
        # draw cur_max
        if self.cur_max:
            self.draw_Point(context, self.cur_max, [1,0,0])

        
    def draw_Point(self, context, plane, col, linewidth=1, r=3):
        x1, y1, x2, y2 = self.recalc_coords(plane)
        context.set_source_rgb(col[0], col[1], col[2])
        context.set_line_width (linewidth)
        context.move_to(x1 + r, y1)
        context.arc(x1, y1, r, 0, 2 * pi)    
        context.fill_preserve()
        context.set_source_rgb(1,0,1)
        context.stroke() 
        context.set_source_rgb(col[0], col[1], col[2])
        context.set_line_width (linewidth)
        context.move_to(x2 + r, y2)
        context.arc(x2, y2, r, 0, 2 * pi)    
        context.fill_preserve()
        context.set_source_rgb(1,1,1)
        context.stroke() 

    def draw_GreatCircle(self,context, plane1, plane2, col=[.5,.5,.5], linewidth=1):
        pplane = plane1.get_perpendicular_between(plane2).normal()
        points = []
        for angle in range (0, 180, 1):
            a = pplane.rotated(angle)
            points.append(a)
        # draw lines
        for i in range(1, len(points)):
            point = points[i]
            point_back = points[i-1]
            xb1,yb1, xb2,yb2 = self.recalc_coords(point_back)
            x1,y1, x2,y2 = self.recalc_coords(point)
            if abs(x1-xb1)>20 or abs(x2-xb2)>20: continue
            context.set_source_rgb(col[0], col[1], col[2])
            context.set_line_width (linewidth)
            context.move_to(xb1, yb1)
            context.line_to(x1, y1)        
            context.stroke()
            context.set_source_rgb(col[0], col[1], col[2])
            context.set_line_width (linewidth)
            context.move_to(xb2, yb2)
            context.line_to(x2, y2)        
            context.stroke()

    def draw_Belt(self,context, pplane, col=[0,0,0], linewidth=1):
        points = []
        for angle in range (0, 180, 1):
            a = pplane.rotated(angle)
            points.append(a)
        # draw lines
        for i in range(1, len(points)):
            point = points[i]
            point_back = points[i-1]
            xb1,yb1, xb2,yb2 = self.recalc_coords(point_back)
            x1,y1, x2,y2 = self.recalc_coords(point)
            if abs(x1-xb1)>20 or abs(x2-xb2)>20: continue
            context.set_source_rgb(col[0], col[1], col[2])
            context.set_line_width (linewidth)
            context.move_to(xb1, yb1)
            context.line_to(x1, y1)        
            context.stroke()
            context.set_source_rgb(col[0], col[1], col[2])
            context.set_line_width (linewidth)
            context.move_to(xb2, yb2)
            context.line_to(x2, y2)        
            context.stroke()

    def draw_Scats(self, context, scats):
        prof_vals = scats[0]
        prof_dirs = scats[1]
        for i in range (len(prof_dirs)):
            dir = prof_dirs[i]
            val = prof_vals[i]
            self. draw_Arrow(context, self.cur_max, dir, [0,0,0],.5, val, False)
    def draw_Arrow(self, context, plane, direction, col, linewidth=2, \
                   Arrow_length=20, Plot_triangle=True):
        a = (plane.dir - direction) % 360 
        if (a>90 and a<180) or (a<360 and a>270):
            direction = (direction+180)%360
        al = Arrow_length# arrow length
        dplane = plane.get_perpendicular_between(Plane(direction, .0001)).normal()
        angle_val = dplane.return_angle_between(plane)
        angles_sub = dplane.dir-plane.dir
        points = [] # list of points in a profile
        if (angles_sub>0 and angles_sub<180) or\
           (angles_sub<-180 and angles_sub>-360):
            for angle in range(angle_val, angle_val+al, 2):
                a = dplane.rotated(-1*angle)
                if a.dip > 0: a = Plane(a.dir+180, a.dip*-1)
                points.append(a)
        else:
            for angle in range(angle_val, angle_val+al, 2):
                a = dplane.rotated(angle)
                if a.dip > 0: a = Plane(a.dir+180, a.dip*-1)
                points.append(a)
        # draw lines
        for i in range(1, len(points)):
            point = points[i]
            point_back = points[i-1]
            xb1,yb1, xb2,yb2 = self.recalc_coords(point_back)
            x1,y1, x2,y2 = self.recalc_coords(point)
            if abs(x1-xb1)>20 or abs(x2-xb2)>20: continue
            context.set_source_rgb(col[0], col[1], col[2])
            context.set_line_width (linewidth)
            context.move_to(xb1, yb1)
            context.line_to(x1, y1)        
            context.stroke()
            context.set_source_rgb(col[0], col[1], col[2])
            context.set_line_width (linewidth)
            context.move_to(xb2, yb2)
            context.line_to(x2, y2)        
            context.stroke()
        # draw triangle
        if not Plot_triangle: return
        x, y, xn, yn = self.recalc_coords(points[-2])
        x1, y1, x1n, y1n = self.recalc_coords(points[-1])
        angl= atan2((y1-y),(x1-x)) + (radians(90))
        angln= atan2((y1n-yn),(x1n-xn)) + (radians(90))
        rv = 20 # length of a triangle lines
        xv1, yv1 = x1-sin(angl+radians(10))*rv, y1+cos(angl+radians(10))*rv
        xv2, yv2 = x1-sin(angl-radians(10))*rv, y1+cos(angl-radians(10))*rv
        xv1n, yv1n = x1n-sin(angln+radians(10))*rv,y1n+cos(angln+radians(10))*rv
        xv2n, yv2n = x1n-sin(angln-radians(10))*rv,y1n+cos(angln-radians(10))*rv
        #line xv1,yv1 - x1,y1
        context.set_source_rgb(col[0], col[1], col[2])
        context.set_line_width (.5*linewidth)
        context.move_to(xv1, yv1)
        context.line_to(x1, y1)        
        context.stroke()
        context.set_source_rgb(col[0], col[1], col[2])
        context.set_line_width (.5*linewidth)
        context.move_to(xv1n, yv1n)
        context.line_to(x1n, y1n)        
        context.stroke()
        #line xv2,yv2 - x1,y1
        context.set_source_rgb(col[0], col[1], col[2])
        context.set_line_width (.5*linewidth)
        context.move_to(xv2, yv2)
        context.line_to(x1, y1)        
        context.stroke()
        context.set_source_rgb(col[0], col[1], col[2])
        context.set_line_width (.5*linewidth)
        context.move_to(xv2n, yv2n)
        context.line_to(x1n, y1n)        
        context.stroke()

            


    def recalc_coords(self, plane):
        dr, dp = plane.dir, plane.dip
        x1 = dr/360*self.width 
        y1 = self.cy - dp/90*self.height/2.0
        x2 = ((dr+180)%360)/360*self.width
        y2 = dp/90*self.height/2.0 + self.cy
        return x1, y1, x2, y2    
    
    def get_widget_coords(self, x, y):
        if y < self.height/2:
            dp = (1-(self.height/2-y)/(self.height/2))*90
            dr = 360-(self.width-x)/self.width*360
        else:
            dp = (self.height/2-(y-self.height/2))/(self.height/2)*90 
            dr = (360-(self.width-x)/self.width*360+180) % 360
        return dr, dp      
